#
# peerscape.profile.event
#
# Copyright 2008 Helsinki Institute for Information Technology
# and the authors.
#
# Authors: Ken Rimey <rimey@hiit.fi>
#

# Permission is hereby granted, free of charge, to any person
# obtaining a copy of this software and associated documentation files
# (the "Software"), to deal in the Software without restriction,
# including without limitation the rights to use, copy, modify, merge,
# publish, distribute, sublicense, and/or sell copies of the Software,
# and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

"""
Post a "What's New" event to a dataset.

Events can be posted for any kind of dataset.  An event includes some
text and an optional IID reference.  When the dataset is a personal or
group profile, each event can be either public or restricted.

>>> import time
>>> from peerscape import DB

>>> db = DB()
>>> p = db.init_persona('Test User')
>>> iid = db.create_dataset('Test Content')

>>> event = db.get_last_event(iid)
>>> event.keys()
[u'timestamp']

>>> db.post_event(iid, 'Testing...')
>>> event = db.get_last_event(iid)
>>> event['comment']
u'Testing...'

>>> db.post_event(iid, "It's my birthday!", p)
>>> event = db.get_last_event(iid)
>>> event['comment']
u"It's my birthday!"
>>> event['iid'] == p
True

>>> db.get_profile_events(p, field='comment')
[]
>>> event = db.get_last_event(p)
>>> event.keys()
[u'timestamp']

>>> db.post_event(p, 'Hello world!')
>>> db.get_profile_events(p, field='comment')
[u'Hello world!']
>>> event = db.get_last_event(p)
>>> event['comment']
u'Hello world!'

>>> t0 = db.get_json(p, '/info/modified')['timestamp']
>>> time.sleep(1)

>>> db.post_event(p, 'Hello friends!', public=False)
>>> db.get_profile_events(p, field='comment')
[u'Hello world!', u'Hello friends!']
>>> event = db.get_last_event(p)
>>> event['comment']
u'Hello friends!'

>>> db.clear_persona()
>>> db.get_profile_events(p, field='comment')
[u'Hello world!']
>>> event = db.get_last_event(p)
>>> event['comment']
u'Hello world!'

>>> t1 = db.get_json(p, '/info/modified')['timestamp']
>>> len(t0) == len(t1)
True
>>> t1 > t0
True

>>> db.close()
"""

from __future__ import with_statement

UNIVERSAL_PATH = '/info/modified'
PUBLIC_PATH = '/public/event.json'
RESTRICTED_PATH = '/restricted/event.json'

class EventDBMixin(object):
    def post_event(self, iid, comment, reference_iid=None, public=True):
        """Post an event explaining an update to the dataset."""
        event = dict(comment=comment)
        if reference_iid:
            event.update(iid=reference_iid)

        with self.write_transaction():
            if self.get_dataset_type(iid) not in ('principal', 'group'):
                self.update_timestamp(iid, UNIVERSAL_PATH, event)
            elif public:
                self.update_timestamp(iid, PUBLIC_PATH, event)
                self.update_timestamp(iid, UNIVERSAL_PATH)
            else:
                cipher = self.get_group_cipher(iid)
                self.update_timestamp(iid, RESTRICTED_PATH, event, cipher=cipher)
                self.update_timestamp(iid, UNIVERSAL_PATH)

    def post_nonevent(self, iid):
        """Note quietly that a personal or group profile has been updated."""
        self.update_timestamp(iid, UNIVERSAL_PATH)

    def get_last_event(self, iid):
        """Return a dictionary with the data for the last posted event."""
        with self.read_transaction():
            if self.get_dataset_type(iid) in ('principal', 'group'):
                events = self.get_profile_events(iid)
                if events:
                    return events[-1]

            return self.get_json(iid, UNIVERSAL_PATH)

    def get_profile_events(self, iid, field=None):
        events = []
        with self.read_transaction():
            event = self.get_json(iid, PUBLIC_PATH)
            if event is not None:
                events.append(event)

            try:
                cipher = self.get_group_cipher(iid)
                event = self.get_json(iid, RESTRICTED_PATH, cipher=cipher)
                if event is not None:
                    events.append(event)
            except LookupError:
                pass

        events.sort(key=lambda event: event.get('timestamp'))
        if field is None:
            return events
        else:
            return [event.get(field) for event in events]

if __name__ == '__main__':
    import doctest
    doctest.testmod()
